package vmo;

import java.awt.Font;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;


import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.Sys;
import org.lwjgl.opengl.ContextAttribs;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.PixelFormat;
import org.lwjgl.util.vector.Matrix4f;
import org.newdawn.slick.TrueTypeFont;
import org.newdawn.slick.util.ResourceLoader;

import client.ColourMap;
import client.Player_Scene;

import server.Generators;
import server.Server;
import shared.GUIBase;
import shared.MouseHook;
import shared.Scene;
import shared.SceneManager;

public class Game implements SceneManager {

	public static SceneManager g_manager;
	long m_lastframe;
	int m_vshader,m_fshader,m_pshader,m_tintvar,m_viewvar,m_objvar;
	Scene m_currentscene;
	GameManager m_gman;
	
	static Server g_server;
	static Thread g_serverthread;
	
	MouseHook m_mouse;
	
	public static float m_tickspersecond;
	
	public Game()
	{
		g_manager=this;
		g_server=null;
		g_serverthread=null;
		Generators.Initialize();
		m_lastframe=0;
		m_tickspersecond=Sys.getTimerResolution();
		//establish window
		try {
			PixelFormat pixelFormat = new PixelFormat();
			ContextAttribs contextAtrributes = new ContextAttribs(3, 2)
				.withProfileCore(true)
				.withForwardCompatible(true);
			
			Display.setDisplayMode(new DisplayMode(800, 600));
			Display.setTitle("Warped Realities Online");
			Display.create(pixelFormat, contextAtrributes);

			GL11.glEnable(GL11.GL_BLEND);
			GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
			//GL11.glAlphaFunc(GL11.GL_GREATER, 0.1f);			
			
			GL11.glViewport(0, 0, 800, 600);
		} catch (LWJGLException e) {
			e.printStackTrace();
			System.exit(0);
		}	

		LoadShaders();		
		m_gman=new GameManager();
		
		int []var=new int[3];
		var[0]=m_tintvar; var[1]=m_viewvar; var[2]=m_objvar;
		
		//m_currentscene=new Lobby(var);
		m_currentscene=new Player_Scene(var);
		
		m_mouse=new MouseHook();
		m_currentscene.Start(m_mouse);
		//load font	

	}
	
	private int loadShader(String filename, int type) {
		StringBuilder shaderSource = new StringBuilder();
		int shaderID = 0;
		
		try {
			BufferedReader reader = new BufferedReader(new FileReader(filename));
			String line;
			while ((line = reader.readLine()) != null) {
				shaderSource.append(line).append("\n");
			}
			reader.close();
		} catch (IOException e) {
			System.err.println("Could not read file.");
			e.printStackTrace();
			System.exit(-1);
		}
		
		shaderID = GL20.glCreateShader(type);
		GL20.glShaderSource(shaderID, shaderSource);
		GL20.glCompileShader(shaderID);
		
		if (GL20.glGetShader(shaderID, GL20.GL_COMPILE_STATUS) == GL11.GL_FALSE) {
			System.err.println("Could not compile shader.");
			System.exit(-1);
		}
			
		return shaderID;
	}

	public void LoadShaders()
	{
		m_vshader=this.loadShader("assets/shaderv.txt", GL20.GL_VERTEX_SHADER);
		m_fshader=this.loadShader("assets/shaderf.txt", GL20.GL_FRAGMENT_SHADER);
		m_pshader=GL20.glCreateProgram();
		GL20.glAttachShader(m_pshader, m_vshader);
		GL20.glAttachShader(m_pshader, m_fshader);
		
		GL20.glBindAttribLocation(m_pshader, 0, "in_Position");
		GL20.glBindAttribLocation(m_pshader, 1, "in_TextureCoord");
		GL20.glLinkProgram(m_pshader);
		GL20.glValidateProgram(m_pshader);
		
		m_tintvar=GL20.glGetUniformLocation(m_pshader,"in_color");
		m_viewvar=GL20.glGetUniformLocation(m_pshader,"projMatrix");
		m_objvar=GL20.glGetUniformLocation(m_pshader,"modelMatrix");

	}	
	
	public void End()
	{
		//delete shader
		GL20.glUseProgram(0);
		GL20.glDetachShader(m_pshader, m_vshader);
		GL20.glDetachShader(m_pshader, m_fshader);
		GL20.glDeleteShader(m_vshader);
		GL20.glDeleteShader(m_fshader);
		GL20.glDeleteProgram(m_pshader);	
		//clean up		
		m_mouse.Discard();
		m_currentscene.End();
			
		if (g_server!=null)
		{
			g_serverthread.interrupt();
			g_server.Discard();
		}
		Display.destroy();	
		

	}
	
	public void Run()
	{
		//handle timing here
		while (!Display.isCloseRequested()) {
			
			Display.sync(60);
			long t=Sys.getTime();
			long dt=t-m_lastframe;
			m_lastframe=t;
			//timekeeping
			Update(dt);
			

		}
		
		
	}
	
	public void Update(float dt)
	{
		//update
		m_currentscene.Update(dt);
		m_mouse.Update();
		m_gman.Update(dt);
		
		//render
		Draw();
	}
	
	void Draw()
	{

		GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
		GL20.glUseProgram(m_pshader);

		GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
		GL11.glEnable(GL11.GL_BLEND);
		
		m_currentscene.Draw();
		
		GL20.glUseProgram(0);	
		Display.update(true);
	}

	@Override
	public void SwapScene(Scene scene) {
		// TODO Auto-generated method stub
		m_currentscene.End();
		m_currentscene=scene;
		m_mouse.Clean();
		m_currentscene.Start(m_mouse);
	}
	
}
